package price;

import java.math.BigDecimal;

/**
 * Created by wangxingsheng on 2019/5/21.
 * <p>
 * 提供精确的浮点数运算（运用场景：金额...）
 * 提供方法：
 * 加: add <string、double、float>
 * 减: sub <string、double、float>
 * 乘: mul <string、double、float>
 * 除: div <string、double、float>
 * <p>
 * <p>
 * 原因（1）：
 * Java中的简单浮点数类型float和double不能够进行运算。偶然时会出现错误结果，如下：
 * System.out.println(0.05 + 0.01);  //0.060000000000000005
 * System.out.println(1.0 - 0.42);   //0.5800000000000001
 * System.out.println(4.015 * 100);  //401.49999999999994
 * System.out.println(123.3 / 100);  //1.2329999999999999
 * 原样（2）：
 * 浮点数类型的toString会出现非原样输出的情况，如下：
 * System.out.println(Float.valueOf("123456789.12")); //1.23456792E8
 */
public class Arith {
    // 默认除法运算精度
    private static final int DEF_DIV_SCALE = 4;

    // 这个类不能实例化
    private Arith() {
    }

    public static String print(float v) {
        return new BigDecimal(Float.toString(v)).toString();
    }

    public static String print(double v) {
        return new BigDecimal(Double.toString(v)).toString();
    }

    /*

        float

     */

    public static BigDecimal add(float v1, float v2) {
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));

        return b1.add(b2);
    }

    public static BigDecimal sub(float v1, float v2) {
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.subtract(b2);
    }

    public static BigDecimal mul(float v1, float v2) {
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.multiply(b2);
    }

    public static BigDecimal div(float v1, float v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    public static BigDecimal div(float v1, float v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
    }

    /*

        double

     */

    public static BigDecimal add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2);
    }

    public static BigDecimal sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2);
    }


    public static BigDecimal mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2);
    }

    public static BigDecimal div(double v1, double v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    public static BigDecimal div(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
    }

    /*

        string

     */

    public static BigDecimal add(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2);
    }

    public static BigDecimal sub(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2);
    }


    public static BigDecimal mul(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2);
    }

    public static BigDecimal div(String v1, String v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    public static BigDecimal div(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
    }
}
